﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using DB.SchemaSync.Library.Interfaces;

namespace DB.SchemaSync.Library
{
	public class SqlScriptRunner
	{
		public SqlScriptRunner(Type providerType)
		{
			Provider = Activator.CreateInstance(providerType) as IDbConnectionProvider;
		}

		public SqlScriptRunner(IDbConnectionProvider provider)
		{
			Provider = provider;
		}

		public IDbConnectionProvider Provider { get; }

		public static void Run(IDbConnection connection, SqlSyntax syntax, SchemaComparison comparison)
		{
			string script = string.Join("\r\n", comparison.GetScriptCommands(syntax));
			Run(connection, syntax, script);
		}


		public static void Run(IDbConnection connection, SqlSyntax syntax, IEnumerable<string> commands)
		{
			string script = string.Join("\r\n", commands);
			Run(connection, syntax, script);
		}

		public static void Run(IDbConnection connection, SqlSyntax syntax, string script)
		{
            //如果连接没有打开则打开
		    var connstate = connection.State;
		    if (connstate != ConnectionState.Open)
		    {
		        connection.Open();
		    }
			using (var txn = connection.BeginTransaction())
			{
				try
				{
					string[] statements = script
						.Split(new string[] { syntax.BatchSeparator }, StringSplitOptions.RemoveEmptyEntries)
						.Where(s => !s.StartsWith(syntax.CommentStart)).ToArray();

					foreach (string statement in statements)
					{
						using (var cmd = connection.CreateCommand())
						{
							cmd.CommandText = syntax.ApplyDelimiters(statement) ;
							cmd.Connection = connection;
							cmd.Transaction = txn;
							cmd.ExecuteNonQuery();
						}
					}
				}
				catch
				{
					txn.Rollback();
					throw;
				}
				txn.Commit();
			}

		    //如果连接没有打开则关闭
            if (connstate != ConnectionState.Open)
		    {
                connection.Close();
		    }
		}

		public void Run(string connectionString, string script)
		{
			if (Provider == null) throw new NullReferenceException("Provider type was not set.");

			var syntax = Provider.GetDefaultSyntax();
			using (var cn = Provider.ConnectionMethod.Invoke(connectionString))
			{
				cn.Open();
				Run(cn, syntax, script);
			}
		}

		public void RunFile(string connectionString, string fileName)
		{
			string script = File.ReadAllText(fileName);
			Run(connectionString, script);
		}
	}
}